package com.example.fdbus;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.Nullable;

import com.example.fdbus.request.RequestBean;
import com.example.fdbus.request.RequestParamter;
import com.google.gson.Gson;

import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.HashMap;

public class NameServerManager extends Service {
    private static final String TAG = NameServerManager.class.getName();
    public static final int TYPE_GET = 0x01;
    public static final int TYPE_INVOKE = 0x02;

    private HashMap<String, WebSocket> hashMap = new HashMap();
    private Gson gson = new Gson();

    private MyWebSocketServer webSocketServer;

    @Override
    public void onCreate() {
        super.onCreate();

        webSocketServer = new MyWebSocketServer();
        webSocketServer.start();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

        try {
            webSocketServer.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private class MyWebSocketServer extends WebSocketServer {
        MyWebSocketServer() {
            super(new InetSocketAddress(8302));
        }

        @Override
        public void onOpen(WebSocket conn, ClientHandshake handshake) {
            String address = conn.getRemoteSocketAddress().getAddress().getHostAddress();
            Log.i(TAG, "onOpen: address " + address);
            hashMap.put(address, conn);
        }

        @Override
        public void onClose(WebSocket conn, int code, String reason, boolean remote) {
            Log.i(TAG, "onClose , reason " + reason);
        }

        @Override
        public void onMessage(WebSocket conn, String message) {

        }

        @Override
        public void onMessage(WebSocket conn, ByteBuffer message) {
            byte[] b = new byte[message.remaining()];
            message.get(b);
            String str = new String(b);

            Log.i(TAG, "onMessage: " + str);

            String result = dealRequest(str);
            hashMap.get(conn.getRemoteSocketAddress().getAddress().getHostAddress()).send(
                    result
            );
        }

        @Override
        public void onError(WebSocket conn, Exception ex) {
            Log.e(TAG, "onClose , reason " + ex.toString());
        }

        @Override
        public void onStart() {

        }
    }

    public String dealRequest(String str) {
        RequestBean requestBean = gson.fromJson(str, RequestBean.class);

        int type = requestBean.getType();

        switch (type) {
            case TYPE_GET: {
                Method method = IPCNameManager.INSTANCE.getNameCenter().getMethod(requestBean);
                Object[] objects = makeParameterObject(requestBean);
                Object object = null;
                try {
                    object = method.invoke(null, objects);
                    IPCNameManager.INSTANCE.getNameCenter().putObject(requestBean.getClassName(), object);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return gson.toJson(object);
            }
            case TYPE_INVOKE: {
                Object object = IPCNameManager.INSTANCE.getNameCenter().getObject(requestBean.getClassName());
                Method method = IPCNameManager.INSTANCE.getNameCenter().getMethod(requestBean);
                Object[] args = makeParameterObject(requestBean);

                Object result = null;
                try {
                    result = method.invoke(object, args);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                return gson.toJson(result);
            }
        }
        return null;
    }

    private Object[] makeParameterObject(RequestBean requestBean) {
        if (requestBean.getRequestParamters().length <= 0) return null;

        Object[] objects = new Object[requestBean.getRequestParamters().length];

        for (int i = 0; i < requestBean.getRequestParamters().length; ++i) {
            RequestParamter paramter = requestBean.getRequestParamters()[i];
            Class clz = IPCNameManager.INSTANCE.getNameCenter().getClassType(paramter.getParameterClassName());
            objects[i] = gson.fromJson(paramter.getParameterValue(), clz);
        }

        return objects;
    }
}
